home *** CD-ROM | disk | FTP | other *** search
/ Apple WWDC 1996 / WWDC96_1996 (CD).toast / Technology Materials / Multiprocessing SDK / Sample Code / PowerFrax / sources / HFMultiprocessingPPC.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-03  |  7.7 KB  |  205 lines  |  [TEXT/CWIE]

  1. /************************************************************************************/
  2. /*                                                                                    */
  3. /* HappyFracs                                                                        */
  4. /* ----------                                                                        */
  5. /*                                                                                    */
  6. /*    © DayStar Digital, Inc. 1995-1996                                                */
  7. /*    All Rights Reserved.                                                            */
  8. /*                                                                                    */
  9. /************************************************************************************/
  10.  
  11. #include <MP.h>
  12.  
  13. /*----------------------------------------------------------------------------------*/
  14. #define kTMCreate            1
  15. #define kTMRun                2
  16. #define kTMQuit                3
  17. #define kTMReady            4
  18.  
  19. /*----------------------------------------------------------------------------------*/
  20. typedef OSErr (*MPWorkFunction)( void *params );
  21.  
  22. typedef struct {
  23.     MPTaskID taskID;
  24.     MPQueueID appToTask;
  25.     MPQueueID taskToApp;
  26.     MPWorkFunction workFunction;
  27.     void *params;
  28.     } sTaskData, *sTaskDataPtr;
  29.  
  30. /*----------------------------------------------------------------------------------*/
  31. OSErr fMPInitialize( long *numProcessors );
  32. OSErr fMPTasksCreate( long numTasks );
  33. void fMPTaskRun( long whichTask, MPWorkFunction workFunction, void *params );
  34. void fMPTaskWait( long whichTask );
  35. void fMPTasksQuit( long numTasks );
  36. static OSStatus fTask( void *theParameter );
  37.  
  38. /*----------------------------------------------------------------------------------*/
  39. sTaskDataPtr gTaskData;            /* Task information slots                            */
  40.  
  41. /*==================================================================================*/
  42. OSErr fMPInitialize( long *numProcessors ) {
  43. /* This function is called when PowerFrax starts up. It makes sure the                */
  44. /* multiprocessing library is loaded and tells PowerFrax how many processors are    */
  45. /* available.                                                                        */
  46.  
  47.     OSErr theErr;
  48.  
  49.     theErr = noErr;
  50.  
  51.     /* Check that the MP library is present */
  52.     if( theErr == noErr )
  53.         if( !MPLibraryIsLoaded() )
  54.             theErr = 1;
  55.  
  56.     /* Get the processor count */
  57.     if( theErr == noErr )
  58.         *numProcessors = MPProcessors();
  59.  
  60.     return( theErr );
  61.     }
  62.  
  63. /*==================================================================================*/
  64. OSErr fMPTasksCreate( long numTasks ) {
  65. /* PowerFrax calls this function soon after startup and everytime the user selects    */
  66. /* a different number of processors to use from the Multiprocessing menu.            */
  67. /* It creates one communication 'slot' for each task, it creates the queues used to    */
  68. /* communicate with the task, and creates the task itself passing the address of    */
  69. /* the 'slot' to the task as its sole parameter.                                    */
  70. /* Each task is asked to acknowledge creation.                                        */
  71.  
  72.     long i;
  73.     OSErr theErr;
  74.     long message;
  75.  
  76.     theErr = noErr;
  77.  
  78.     /* Create an array of sTaskDataPtr (defined above) with one 'slot' for each        */
  79.     /* task to be created.                                                            */
  80.     gTaskData = NULL;
  81.     if( theErr == noErr ) {
  82.         gTaskData = (sTaskDataPtr)NewPtrClear( numTasks * sizeof( sTaskData ) );
  83.         if( gTaskData == NULL )
  84.             theErr = MemError();
  85.         }
  86.  
  87.     /* Create one task per processor */
  88.     for( i = 0; i < numTasks && theErr == noErr; i++ ) {
  89.         /* Create the message queues by which to communicate the action                */
  90.         /* messages the app. sends to the tasks, and by which to receive the        */
  91.         /* status message returned by the tasks.                                    */
  92.         if( theErr == noErr )
  93.             theErr = MPCreateQueue( &gTaskData[i].appToTask );
  94.         if( theErr == noErr )
  95.             theErr = MPCreateQueue( &gTaskData[i].taskToApp );
  96.         if( theErr == noErr )
  97.             theErr = MPCreateTask( fTask, &gTaskData[i], 2048, NULL, NULL, NULL, 0, &gTaskData[i].taskID );
  98.         if( theErr == noErr ) {
  99.             MPNotifyQueue( gTaskData[i].appToTask, (void *)kTMCreate, NULL, NULL );
  100.             MPWaitOnQueue( gTaskData[i].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
  101.             }
  102.         }
  103.     
  104.     return( theErr );
  105.     }
  106.  
  107. /*==================================================================================*/
  108. void fMPTaskRun( long whichTask, MPWorkFunction workFunction, void *params ) {
  109. /* Prepare data for the specified task and set it running. Normally each parameter    */
  110. /* passed to this type of function would be copied into the gTaskData block for the    */
  111. /* specified task. However, since PowerFrax provides MP services to any fractal        */
  112. /* generator that requests it, the parameters are instead passed as an arbitrary    */
  113. /* block of data. Since the parameters are different for each request PowerFrax        */
  114. /* maintains one unique block to use for each available task.                        */
  115.  
  116.     gTaskData[whichTask].workFunction = workFunction;
  117.     gTaskData[whichTask].params = params;
  118.  
  119.     MPNotifyQueue( gTaskData[whichTask].appToTask, (void *)kTMRun, NULL, NULL );
  120.     }
  121.  
  122. /*==================================================================================*/
  123. void fMPTaskWait( long whichTask ) {
  124. /* Wait until the specified task is finished doing work. PowerFrax operates by        */
  125. /* starting one scanline per task and then waiting for all of the tasks to finish.    */
  126. /* If continues to do this until the image is finished or more than a tenth of a    */
  127. /* second has elapsed. The process is repeated if necessary every time a NULL event    */
  128. /* is received in the WaitNextEvent() loop.                                            */
  129.  
  130.     long message;
  131.  
  132.     MPWaitOnQueue( gTaskData[whichTask].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
  133.     }
  134.  
  135. /*==================================================================================*/
  136. void fMPTasksQuit( long numTasks ) {
  137. /* PowerFrax calls this function before quitting and everytime the user selects a    */
  138. /* different number of processors to use from the Multiprocessing menu.                */
  139. /* The tasks are notified that they are about to be terminated. Once they            */
  140. /* acknowledge, they are terminated and all the resources they were using are        */
  141. /* deallocated.                                                                        */
  142.  
  143.     long i;
  144.     long message;
  145.  
  146.     if( gTaskData != NULL ) {
  147.         for( i = 0; i < numTasks; i++ ) {
  148.             /* If this task was successfully created then try to close it down        */
  149.             /* properly.                                                            */
  150.             if( gTaskData[i].appToTask != NULL &&
  151.                 gTaskData[i].taskToApp != NULL &&
  152.                 gTaskData[i].taskID != NULL ) {
  153.                 MPNotifyQueue( gTaskData[i].appToTask, (void *)kTMQuit, NULL, NULL );
  154.                 MPWaitOnQueue( gTaskData[i].taskToApp, (void **)&message, NULL, NULL, kDurationForever );
  155.                 }
  156.             /* Delete the task resources */
  157.             if( gTaskData[i].taskID != NULL )
  158.                 MPTerminateTask( gTaskData[i].taskID, noErr );
  159.             if( gTaskData[i].taskToApp != NULL )
  160.                 MPDeleteQueue( gTaskData[i].taskToApp );
  161.             if( gTaskData[i].appToTask != NULL )
  162.                 MPDeleteQueue( gTaskData[i].appToTask );
  163.             }
  164.         DisposePtr( (Ptr)gTaskData );
  165.         }
  166.     }
  167.  
  168. /*==================================================================================*/
  169. /*==================================================================================*/
  170. static OSStatus fTask( void *theParameter ) {
  171. /* This is the actual task. The parameter was provided at task creation time and in    */
  172. /* this case is a pointer to a 'slot' containing the information for use by this    */
  173. /* task. Note that the function that performs the actual work and the parameters to    */
  174. /* use are variables that are established in fMPTaskRun(). This lets PowerFrax        */
  175. /* provide MP services to any fractal generator willing to provide such a function.    */
  176.  
  177.     Boolean finished;
  178.     sTaskDataPtr p;
  179.     long message;
  180.  
  181.     /* The following statement is executed once, immediately after task creation */
  182.     p = (sTaskDataPtr)theParameter;
  183.  
  184.     finished = false;
  185.     while( !finished ) {
  186.         MPWaitOnQueue( p->appToTask, (void **)&message, NULL, NULL, kDurationForever );
  187.         switch( message ) {
  188.             case kTMCreate:
  189.                 break;
  190.             case kTMRun:
  191.                 p->workFunction( p->params );
  192.                 break;
  193.             case kTMQuit:
  194.                 finished = true;
  195.                 break;
  196.             }
  197.         MPNotifyQueue( p->taskToApp, (void *)kTMReady, NULL, NULL );
  198.         }
  199.  
  200.     return( noErr );
  201.     }
  202.  
  203. /*==================================================================================*/
  204. /*==================================================================================*/
  205.